#include "system_reset.h"

#include <esp_log.h>
#include <nvs_flash.h>
#include <driver/gpio.h>
#include <esp_partition.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>


/**
 * @brief 日志标签
 */
#define TAG "SystemReset"


/**
 * @brief 系统重置管理类构造函数
 * 
 * @param reset_nvs_pin 重置NVS存储的按钮引脚
 * @param reset_factory_pin 恢复出厂设置的按钮引脚
 */
SystemReset::SystemReset(gpio_num_t reset_nvs_pin, gpio_num_t reset_factory_pin) : reset_nvs_pin_(reset_nvs_pin), reset_factory_pin_(reset_factory_pin) {
    // 配置GPIO引脚为输入模式，带上拉电阻
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = (1ULL << reset_nvs_pin_) | (1ULL << reset_factory_pin_);
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
    gpio_config(&io_conf);
}


/**
 * @brief 检查重置按钮状态
 * 
 * 检测按钮是否被按下，并执行相应的重置操作
 */
void SystemReset::CheckButtons() {
    // 检查恢复出厂设置按钮
    if (gpio_get_level(reset_factory_pin_) == 0) {
        ESP_LOGI(TAG, "Button is pressed, reset to factory");
        ResetNvsFlash();
        ResetToFactory();
    }

    // 检查重置NVS按钮
    if (gpio_get_level(reset_nvs_pin_) == 0) {
        ESP_LOGI(TAG, "Button is pressed, reset NVS flash");
        ResetNvsFlash();
    }
}

/**
 * @brief 重置NVS闪存存储
 * 
 * 清除NVS中存储的配置数据并重新初始化
 */
void SystemReset::ResetNvsFlash() {
    ESP_LOGI(TAG, "Resetting NVS flash");
    // 擦除NVS闪存
    esp_err_t ret = nvs_flash_erase();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to erase NVS flash");
    }
    // 重新初始化NVS闪存
    ret = nvs_flash_init();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize NVS flash");
    }
}

/**
 * @brief 恢复出厂设置
 * 
 * 擦除OTA数据分区并重启设备
 */
void SystemReset::ResetToFactory() {
    ESP_LOGI(TAG, "Resetting to factory");
    // 查找并擦除OTA数据分区
    const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
    if (partition == NULL) {
        ESP_LOGE(TAG, "Failed to find otadata partition");
        return;
    }
    esp_partition_erase_range(partition, 0, partition->size);
    ESP_LOGI(TAG, "Erased otadata partition");

    // 3秒后重启系统
    RestartInSeconds(3);
}

/**
 * @brief 延时重启系统
 * 
 * @param seconds 延时重启的秒数
 */
void SystemReset::RestartInSeconds(int seconds) {
    // 倒计时并打印日志
    for (int i = seconds; i > 0; i--) {
        ESP_LOGI(TAG, "Resetting in %d seconds", i);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    // 重启系统
    esp_restart();
}
